package swu.commodity;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.core.FileItem;
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletFileUpload;
import swu.core.ResponseOperator;
import swu.core.ServletController;

import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.Charset;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.UUID;

@WebServlet(urlPatterns = "/administrator/commodity/*")
public class CommodityOperator extends ServletController
{
    private CommodityService commodityService = null;
    protected SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-mm-dd");

    private static final String UPLOAD_DIRECTORY = "upload";

    private static final int MEMORY_THRESHOLD   = 1024 * 1024 * 3;  // 3MB
    private static final int MAX_FILE_SIZE      = 1024 * 1024 * 40; // 40MB
    private static final int MAX_REQUEST_SIZE   = 1024 * 1024 * 50; // 50MB


    public void init(ServletConfig config)
    {
        CommodityRepo repo = new CommodityRepo();
        commodityService = new CommodityService();
        commodityService.setRepo(repo);
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException
    {
        this.methodRoute(request, response);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException
    {
        this.methodRoute(request, response);
    }

    private void methodRoute(HttpServletRequest request, HttpServletResponse response) throws ServletException
    {
        String uri = request.getRequestURI();
        String method = uri.substring(uri.lastIndexOf("/") + 1);

        try
        {
            if (method.equals("list"))
            {
                this.list(request, response);
            }
            else if (method.equals("add"))
            {
                this.add(request, response);
            }
            else if (method.equals("delete"))
            {
                this.delete(request, response);
            }
            else if (method.equals("edit"))
            {
                this.edit(request, response);
            }
            else if (method.equals("update"))
            {
                this.update(request, response);
            }
            else if (method.equals("search"))
            {
                this.search(request, response);
            }
        } catch (SQLException | IOException e)
        {
            throw new ServletException(e);
        }
    }

    public void list(HttpServletRequest request, HttpServletResponse response) throws ServletException
    {
        try
        {
            List<Commodity> commodities = this.commodityService.getAllCommodities();
            this.responseJson(response, true, commodities);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException
    {
        this.save(request, response);
    }

    private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException
    {
        this.save(request, response);
    }

    private void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException
    {
        int id = Integer.parseInt(request.getParameter("id"));
        this.commodityService.deleteCommodityById(id);
        response.sendRedirect("../list.html");
    }

    private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException
    {
        int id = Integer.parseInt(request.getParameter("id"));
        try
        {
            Commodity commodity = this.commodityService.getCommodityById(id);
            try(Writer writer = response.getWriter())
            {
                String form = this.wrapEditForm(commodity);
                String page  = this.wrapPage(form);
                writer.write(page);
            }
        } catch (SQLException | IOException e)
        {
            throw new ServletException(e);
        }
    }

    private void save(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException
    {
        if (!JakartaServletFileUpload.isMultipartContent(request))
        {
            // 如果不是则停止
            Writer writer = response.getWriter();
            writer.write("Error: 表单必须包含 enctype=multipart/form-data");
            writer.flush();
            return;
        }
        // 配置上传参数
        DiskFileItemFactory factory = DiskFileItemFactory
                .builder()
                .setBufferSize(MEMORY_THRESHOLD)
                .get();

        JakartaServletFileUpload upload = new JakartaServletFileUpload(factory);
        // 设置最大文件上传值
        upload.setFileSizeMax(MAX_FILE_SIZE);
        // 设置最大请求值 (包含文件和表单数据)
        upload.setSizeMax(MAX_REQUEST_SIZE);
        // 中文处理
        upload.setHeaderCharset(Charset.forName("UTF-8"));
        // 构造临时路径来存储上传的文件
        // 这个路径相对当前应用的目录
        String uploadPath = request.getServletContext().getRealPath("./")
                + File.separator + UPLOAD_DIRECTORY;

        // 如果目录不存在则创建
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists())
        {
            uploadDir.mkdir();
        }

        try
        {
            Commodity commodity = new Commodity();
            Charset uft8 = Charset.forName("UTF-8");
            String imageName = UUID.randomUUID().toString();
            // 解析请求的内容提取文件数据
            @SuppressWarnings("unchecked")
            List<FileItem> formItems = upload.parseRequest(request);
            if (formItems != null && formItems.size() > 0)
            {
                // 迭代表单数据
                for (FileItem item : formItems)
                {
                    // 处理不在表单中的字段
                    if (!item.isFormField())
                    {
                        String image = new File(item.getName()).getName();
                        imageName += image.substring(image.lastIndexOf("."));
                        String filePath = uploadPath + File.separator + imageName;
                        File storeFile = new File(filePath);
                        // 在控制台输出文件的上传路径
                        System.out.println(filePath);
                        // 保存文件到硬盘
                        item.write(storeFile.toPath());
                        commodity.setImage(imageName);
                    }
                    else
                    {
                        System.out.println(item.getString(uft8));
                        if (item.getFieldName().equals("id"))
                        {
                            commodity.setId(Integer.parseInt(item.getString()));
                        }
                        else if (item.getFieldName().equals("name"))
                        {
                            commodity.setName(item.getString(uft8));
                        }
                        else if (item.getFieldName().equals("category"))
                        {
                            commodity.setCategory(item.getString(uft8));
                        }
                        else if (item.getFieldName().equals("price"))
                        {
                            commodity.setPrice(Double.valueOf(item.getString(uft8)));
                        }
                        else if (item.getFieldName().equals("origin"))
                        {
                            commodity.setOrigin(item.getString(uft8));
                        }
                        else if (item.getFieldName().equals("productionDate"))
                        {
                            try
                            {
                                commodity.setProductionDate(CommodityService.simpleDateFormat.parse(item.getString(uft8)));
                            } catch (ParseException e)
                            {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                }
            }

            this.commodityService.saveCommodity(commodity);
            response.sendRedirect("../list.html");
        } catch (IOException ex)
        {
            throw new ServletException(ex);
        }
    }

    private void search(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException
    {
        String key = request.getParameter("key");

        try
        {
            List<Commodity> commodities = this.commodityService.searchCommodity(key);

            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setDateFormat(dateFormatter);
            String jsonString = objectMapper.writeValueAsString(commodities);

            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write(jsonString);

        } catch (SQLException | IOException e)
        {
            throw new ServletException(e);
        }
    }

    private String wrapTable(List<Commodity> commodities)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("<table class='bs'>\n");
        sb.append("<tr><th>编号</th><th>商品名</th><th>产地</th><th>价格</th><th>分类</th><th>生产日期</th><th>图片</th><th></th><th></th></tr>\n");
        for (Commodity commodity : commodities)
        {
            sb.append("<tr>");
            sb.append("<td class='centr'>").append(commodity.getId()).append("</td>");
            sb.append("<td>").append(commodity.getName()).append("</td>");
            sb.append("<td>").append(commodity.getOrigin()).append("</td>");
            sb.append("<td class='centr'>").append(commodity.getPrice()).append("</td>");
            sb.append("<td>").append(commodity.getCategory()).append("</td>");
            sb.append("<td class='centr'>").append(commodity.getProductionDate()).append("</td>");
            sb.append("<td class='centr'><img class='commodity-img-thumbnail' src='/shopping-mall/upload/").append(commodity.getImage()).append("'/></td>");
            sb.append("<td class='centr'><a href='./delete?id=" + commodity.getId() + "'>删除</a></td>");
            sb.append("<td class='centr'><a href='./edit?id=" + commodity.getId() + "'>修改</a></td>");
            sb.append("</tr>");
        }
        sb.append("</table>");
        return sb.toString();
    }

    private String wrapEditForm(Commodity commodity)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("<center><br>")
            .append("<form action=\"./update\" method=\"post\" enctype=\"multipart/form-data\">")
            .append("<input type=\"hidden\" name=\"id\" value=\"" + commodity.getId() + "\"><br><br>")
            .append("商品名：<input type=\"text\" name=\"name\" value=\"" + commodity.getName() + "\"><br><br>")
            .append("产地：<input type=\"text\" name=\"origin\" value=\"" + commodity.getOrigin() + "\"><br><br>")
            .append("价格：<input type=\"text\" name=\"price\" value=\"" + commodity.getPrice() +"\"><br><br>")
            .append("种类：<input type=\"text\" name=\"category\" value=\"" + commodity.getCategory() +"\"><br><br>")
            .append("生产日期：<input type=\"text\" name=\"productionDate\" value=\"" + commodity.getProductionDate() + "\"><br><br>")
            .append("图片：<input type=\"file\" name=\"image\"><br><br>")
            .append("<input type=\"submit\" name=\"submit\" value=\"更新商品\"/>")
            .append("</form>")
            .append("</center>");
        return sb.toString();
    }

}
